/************************************************************************************************
 *   深圳市摩西尔电子有限公司 @版本所有@
 *
 *   此文件用于页面通用调用接口
 *
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2019.01.06
 *      内容 : 所有代码
 ************************************************************************************************/

/* exported set_fold_panel */
/* exported set_combo_val */
/* exported get_single_item_val */
/* exported set_single_item_val */
/* exported load_subpage */
/* exported create_btn_gp_html */
/* exported create_item_text_html */
/* exported create_icon_btn_html */
/* exported mc_ui_page_set_title_val */
/* exported mc_set_fold_panel_switch */
/* exported show_info_massage */
/* exported IEVersion */
/* exported page_construct_ui_step */
/* exported set_text_vertical */
/* exported mc_edit_gp_toggle */
/* exported get_val_from_str_arr */
/* exported mc_page_calc_item_size */
/* exported mc_page_set_attr_contenteditable */
/* exported mc_random_color */
/* exported get_css_class_idx */
/* exported mc_btn_pop_menu */
/* exported mc_add_item_prefix */
/* exported mc_add_css_rules */
/* exported mc_progress_circle */
/* exported get_progress_bar_html */
/* exported get_progress_value */
/* exported get_progress_color */
/* exported add_split_line_vertical */
/* exported get_sum_idx */
/* exported mc_delete_css_rules */
/* exported mc_get_page_zoom */
/* exported construct_page_popup_link_data */
/* exported mc_construct_zoom_mousewheel */
/* exported mc_format_style */
/* exported mc_btn_select_btn_click */
/* exported mc_btn_use_select_btn */
/* exported mc_edit_gp_scroll_event */
/* exported mc_load_file_onclick */
/* exported mc_full_screen */
/* exported mc_prevent_touchmove */
/* exported construct_btn_tabs */


// 工具
/* exported mc_util_copy_obj */
/* exported mc_util_is_array */
/* exported mc_util_is_object */
/* exported mc_util_is_object_dom */
/* exported mc_util_round */
/* exported mc_util_get_url_page_name */
/* exported mc_util_is_weixin */


/* global layer  */
/* global  $ */
/* global mc_sdk_param */
/* global mc_updata_scroll_bar_after_trans */
/* global mc_main_alert_popout */
/* global Swiper */
/* global mc_istouch */


/************************************************************************************************
* 类型:
*    函数
* 功能:
*    定义折叠面板；
* 参数:
*    @param { Promise<String>} el: 需要添加的折叠面板对象
*    @param { Promise<Boolean>} multiple: 是否可同时显示多个折叠面板；
*    @param { Promise<Object>} obj 可选参数:更新滚动条对象; 该对象参数可参考例子；
*    @param { Promise<Boolean>} b_is_click_btn 是否是点击按钮触发 true === 点击按钮 || false === 带标题的折叠栏一整条
*    @param { Promise<Boolean>} func_callback 触发事件后回调函数
* 返回:
*    NA
* 例子:
*    调用例子:
*    var obj_update_scroll = { time: 0,page_id: "#page_container",scroll_id: "#mc_wrap_div"}
*    new mc_set_fold_panel_switch($(".mc_wrap"), false, obj_update_scroll);
* 备注:
*     obj 对象内参数 time 为更新滚动条延迟时间;
*     此方法运用于固定格式的html;
*     <div class="fold_panel_div">
*         <div class="mc_lable_name draw_title">
*             <span class="mc_item_icon 图标class"></span>
*             <span lang_id="标题lang_id"></span>
*             <i class="draw_angle icon-arrow-single-up"></i>
*         </div>
*         <div class="mc_fold_content">
*             <div class="show_or_hide">
*                 <div id="" class="item_wrap_box">折叠面板内容容器</div>
*             </div>
*         </div>
*     </div>
* 修改:
*   1. 类型 : 创建
*      作者 : 巫昭雯
*      时间 : 2020.4.7
*      内容 : 所有代码
************************************************************************************************/
var mc_set_fold_panel_switch = function (el, multiple, obj, b_is_click_btn, func_callback) {
    this.el = el || {};
    this.multiple = multiple || false;
    this.obj = obj || {};
    this.dropdown = fold_panel_dropdown;
    this.b_clk_btn = b_is_click_btn || false;

    // get obj
    var draw_title = this.el.find(".draw_title");
    var draw_angle = this.el.find(".draw_angle");


    // 触发事件对象
    var arr_trigger_obj = draw_title;

    if (b_is_click_btn) {
        arr_trigger_obj = draw_angle;
    } else {
        arr_trigger_obj.css("cursor", "pointer");
    }

    // click params
    var obj_params = {
        el: this.el,
        multiple: this.multiple,
        obj: this.obj,
        b_btn: b_is_click_btn
    };

    arr_trigger_obj.off("click");
    arr_trigger_obj.on("click", obj_params, this.dropdown);

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    折叠面板触发事件
     * 参数:
     *    @param { Promise<String> } e 鼠标事件event
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    $title === 类draw_title的块
     *    $content === 类mc_fold_content块
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-11-12
     *       内容 : 所有代码
     ************************************************************************************************/
    function fold_panel_dropdown(e) {
        var $el = e.data.el;
        var $obj = e.data.obj;
        var time = $obj.time || 0;
        var $this = $(this);

        // 获取折叠标题对象和折叠内容对象
        var $title = $this;
        var $content = $title.next();

        if (e.data.b_btn) {
            $title = $this.parent(".draw_title");
            $content = $title.next();
        }

        if (!$content.is(":animated")) {
            $content.slideToggle();
        }

        $title.parent().toggleClass("draw_open");

        // multiple fold_panel_div
        if (!e.data.multiple) {
            $el.find(".draw_title ").next().not($content).slideUp().parent().removeClass("draw_open");
        }

        // update scroll
        if ("[object Object]" === Object.prototype.toString.call($obj)) {
            if ("{}" !== JSON.stringify($obj)) {
                // 有时候需要延迟
                setTimeout(function () {
                    mc_updata_scroll_bar_after_trans($obj.page_id, $obj.scroll_id);
                }, time);
            }
        }

        // callback
        if ("[object Function]" === Object.prototype.toString.call(func_callback)) {
            // true 收起; false 展开
            func_callback($title, $title.parent().hasClass("draw_open"));
        }
    }
};


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置控件组合并对象的值
 * 参数:
 *    @param { Promise<String>} str_json 固定格式的json字符串
 *    @param { Promise<Boolean>} b_is_combo 合并 === true || 不合并 === false
 * 返回:
 *    @returns { Promise<Object>} 组合对象参数 || false
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function set_combo_val(str_json, b_is_combo) {
    if ("boolean" !== typeof b_is_combo) {
        return false;
    }

    var obj_combo_mode = {};
    var obj_sdk_param = new mc_sdk_param();

    obj_sdk_param.set_json(str_json);
    var ui_param_cnt = obj_sdk_param.get_param_cnt();

    for (var idx_param = 0; idx_param < ui_param_cnt; idx_param++) {
        obj_combo_mode[obj_sdk_param.get_param_name(idx_param)] = b_is_combo;
    }
    return obj_combo_mode;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取控件值单项
 * 参数:
 *    @param { Promise<String>} str_json 固定格式的json字符串
 *    @param { Promise<String>} name_id 需要获取的字串参数name_id
 * 返回:
 *    @returns { Promise<String>} 控件值
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function get_single_item_val(str_json, name_id) {
    var obj_param = new mc_sdk_param();

    obj_param.set_json(str_json);
    return obj_param.get_param_value(name_id);
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置控件值单项
 * 参数:
 *    @param { Promise<String>} str_json 固定格式的json字符串
 *    @param { Promise<String>} name_id 需要获取的字串参数name_id
 *    @param { Promise<String>} new_val 设置的字串新值
 * 返回:
 *    @returns { Promise<String>} 设置之后的json字符串
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function set_single_item_val(str_json, name_id, new_val) {
    var obj_param = new mc_sdk_param();

    obj_param.set_json(str_json);
    if ("" !== new_val) {
        obj_param.set_param_value(name_id, new_val);
    }
    return obj_param.get_json();
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    打开二级页面
 * 参数:
 *    @param { Promise<Object>} str_icon icon图标类
 *    @param { Promise<Object>} str_title 打开层标题名
 *    @param { Promise<Object>} str_url 链接
 *    @param { Promise<Object>} func_callback 确定回调
 *    @param { Promise<Object>} close_fun_callback 打开页面关闭按钮回调
 *    @param { Promise<Object>} area 打开页面范围
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function load_subpage(str_icon, str_title, str_url, func_callback, close_fun_callback, area) {
    if ("string" !== typeof str_icon || "string" !== typeof str_title || "string" !== typeof str_url) {
        return;
    }

    var default_area = ["98%", "98%"];
    var str_combo_title = "<div class='" + str_icon + "'><span style='margin-left:10px;'>" + str_title +
        "</span></div>";

    layer.open({
        type: 2,
        title: str_combo_title,
        shadeClose: false,
        shade: 0.5,
        area: area || default_area,
        resize: false,
        move: false,
        //iframe url
        content: str_url,
        end: function () {
            if ("function" === typeof func_callback) {
                func_callback();
            }
        },
        cancel: function () {
            if ("function" === typeof close_fun_callback) {
                close_fun_callback();
            }
        }
    });
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    创建按钮组html函数
 * 参数:
 *    @param { Promise<Object>} obj 图标和按钮名称键值对象
 *    @param { Promise<String>} fun_name_unit 按钮触发的点击事件函数名称后缀
 * 返回:
 *    @returns { Promise<String>} 生成的html字符串
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯 , 徐烁超
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function create_btn_gp_html(obj, fun_name_unit) {
    var arr_keys = Object.keys(obj);
    var str_btn_name_first = arr_keys[0];
    var str_icon_class_fisrt = "btn_icon " + obj[str_btn_name_first];
    var gp_html = "<div class='btn_outside_box' style='position:relative'>";
    var str_padding_right = "";

    if (1 !== arr_keys.length) {
        str_padding_right = "padding-right:20px";
    }

    gp_html += "<div class='btn_wrap btn_use' lang_id=" + str_btn_name_first + " style='" + str_padding_right + "' onclick=" + str_btn_name_first.toLowerCase() + "_" + fun_name_unit + "(this)><span class= '" + str_icon_class_fisrt +
        "'></span><span class='btn_text' lang_id=" + str_btn_name_first + ">" + str_btn_name_first + "</span></div>";
    if (1 !== arr_keys.length) {
        gp_html += "<div class='select_btn_box btn_select_btn_box' onclick='mc_btn_select_btn_click(this)'><div class='select_btn'></div></div>";
        gp_html += "<div class='select_list btn_select_list' style='position:absolute; margin-top: 10px;padding: 5px;left: 0;max-height: none;border: 1px solid rgb(153, 153, 153);background: rgb(255, 255, 255);display: none;text-align: left; width:auto;white-space: nowrap; '>";
        for (var idx = 0; idx < arr_keys.length; idx++) {
            var btn_name = arr_keys[idx];
            var str_fun_name = btn_name.toLowerCase();
            var btn_icon_class_name = obj[btn_name];

            var icon_class = "btn_icon " + btn_icon_class_name;

            gp_html += "<div class='btn_wrap flex_box_horizontal' lang_id=" + btn_name + " onclick=" + str_fun_name + "_" + fun_name_unit + "(this) style='margin:0 auto;;text-align: left; flex-wrap: nowrap;'>" +
                "<div class= '" + icon_class + "' style='margin-left:5px; width:30px;height:30px;line-height:30px;'></div>" +
                "<span class='btn_text' lang_id=" + btn_name + " style='line-height:30px; padding:0 10px 0px 5px;width:auto'></span>" + "</div>";
        }
        gp_html += "</div></div>";
    } else {
        gp_html += "</div></div>";
    }

    return gp_html;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    按钮选择框事件
 * 参数:
 *    @param {Promise<Object>} this_btn 按钮自身dom元素
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 徐烁超
 *      时间 : 2020.9.30
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_btn_select_btn_click(this_btn) {
    var obj_btn_$ = $(this_btn);
    var str_btn_class = obj_btn_$.attr("class");

    if (-1 === str_btn_class.indexOf("select_btn_rotate")) {
        $(".btn_select_btn_box").removeClass("select_btn_rotate");
        obj_btn_$.addClass("select_btn_rotate");
        $(".btn_select_list").css("display", "none");
        obj_btn_$.next().css("display", "block");
    } else {
        obj_btn_$.removeClass("select_btn_rotate");
        obj_btn_$.next().css("display", "none");
    }
}
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    按钮事件完成后刷新至顶层按钮中
 * 参数:
 *    @param {Promise<Object>} this_btn 按钮自身dom元素
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 徐烁超
 *      时间 : 2020.9.30
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_btn_use_select_btn(this_btn) {
    var obj_btn_$ = $(this_btn);

    if (0 >= obj_btn_$.length) {
        return;
    }
    var mc_click_fn = obj_btn_$[0].onclick;
    var str_icon_class = obj_btn_$.children().eq(0).attr("class");
    var str_text = obj_btn_$.children().eq(1).text();
    var str_lang_id = obj_btn_$.children().eq(1).attr("lang_id");
    var obj_use_btn_$ = obj_btn_$.parent().prevAll(".btn_use");

    if (0 < obj_use_btn_$.length) {
        obj_use_btn_$[0].onclick = mc_click_fn;
        obj_use_btn_$.attr({ "title": str_text, "lang_id": str_lang_id });
        obj_use_btn_$.children().eq(0).attr("class", str_icon_class);
        obj_use_btn_$.children().eq(1).attr({ "title": str_text, "lang_id": str_lang_id }).text(str_text);
    }
}
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    创建控件文字html字符串函数
 * 参数:
 *    @param { Promise<String>} str_langid 文字语言id
 *    @param { Promise<String>} str_item_html 生成的控件字符串
 * 返回:
 *    @returns { Promise<String>} 生成的html字符串 || false
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function create_item_text_html(str_langid, str_item_html) {
    if ("string" !== typeof str_langid || "string" !== typeof str_item_html) {
        return false;
    }

    if ("" === str_langid.trim()) {
        return false;
    }
    var re_html = "<div class='mc_item_wrap'><span class='mc_item_text' lang_id=" + str_langid + ">" + str_langid + "</span>" + str_item_html + "</div>";

    return re_html;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    创建图标按钮html字符串
 * 参数:
 *    @param { Promise<String>} icon_class 需要添加的类
 *    @param { Promise<String>} str_langid 文字语言id
 *    @param { Promise<Function>} fun_click_name 点击触发函数名,若为空则不绑定点击事件; 不为空时该函数需定义在页面，若未定义则会报错; 传参dom;
 * 返回:
 *    @returns { Promise<String>} 生成的html字符串 || false
 * 例子:
 *    NA
 * 备注:
 *    该html字串带有 icon_btn 类
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.6.3
 *      内容 : 所有代码
 ************************************************************************************************/
function create_icon_btn_html(icon_class, str_langid, fun_click_name) {
    if ("string" !== typeof icon_class || "string" !== typeof str_langid) {
        return false;
    }

    var str_click = ("string" === typeof fun_click_name && fun_click_name.trim()) ? "onclick='" + fun_click_name + "(this);'" : "";
    var str_class = "icon_btn " + icon_class;
    var re_html = "<div class='" + str_class + "' lang_id='" + str_langid + "' " + str_click + "><div><span lang_id='" + str_langid + "'></span></div></div>";

    return re_html;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    给按钮组添加title属性(该按钮组具有固定格式);
 * 参数:
 *    @param { Promise<Array>} arr_obj 需要设置的对象数组
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.7
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_ui_page_set_title_val(arr_obj) {
    var arr_len = arr_obj.length;

    for (var idx = 0; idx < arr_len; idx++) {
        var title_name = arr_obj[idx].children[1].innerText;

        if ("undefined" !== typeof title_name) {
            arr_obj[idx].title = title_name;
        }

        arr_obj[idx].title = title_name;
    }
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    显示提示信息
 * 参数:
 *    @param { Promise<String>} str 需要提示的信息；可显示的类型
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.17
 *      内容 : 所有代码
 ************************************************************************************************/
function show_info_massage(str) {
    if ("undefined" !== typeof str.trim()) {
        // layer.alert(str);
        mc_main_alert_popout(str);
    }
}


// 判断ie版本
function IEVersion() {
    //取得浏览器的userAgent字符串
    var userAgent = navigator.userAgent;
    //判断是否IE<11浏览器
    var isIE = -1 < userAgent.indexOf("compatible") && -1 < userAgent.indexOf("MSIE");
    //判断是否IE的Edge浏览器
    var isEdge = -1 < userAgent.indexOf("Edge") && !isIE;
    var isIE11 = -1 < userAgent.indexOf("Trident") && -1 < userAgent.indexOf("rv:11.0");

    if (isIE) {
        var reIE = new RegExp("MSIE (\\d+\\.\\d+);");

        reIE.test(userAgent);
        var fIEVersion = parseFloat(RegExp.$1);

        if (7 === fIEVersion) {
            return 7;
        } else if (8 === fIEVersion) {
            return 8;
        } else if (9 === fIEVersion) {
            return 9;
        } else if (10 === fIEVersion) {
            return 10;
        }
        //IE版本<=7
        return 6;
    } else if (isEdge) {
        //edge
        return "edge";
    } else if (isIE11) {
        //IE11
        return 11;
    }
    //不是ie浏览器
    return -1;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    页面构造步进编辑框,该函数仅为中间转换，因此需要传入正确的数据格式；
 * 参数:
 *    @param { Promise<all>} obj 已定义的需要构造步进编辑框对象
 *    @param { Promise<String>} type 设置步进编辑框的数据类型
 *    @param { Promise<String>} val 设置步进编辑框的初始值
 *    @param { Promise<String>} step_val 设置步进编辑框的步进值
 *    @param { Promise<String>} min_val 设置步进编辑框的最小值
 *    @param { Promise<String>} max_val 设置步进编辑框的最大值
 *    @param { Promise<Function>} val_chg_fun 设置步进编辑框的变动回调函数
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.4.17
 *      内容 : 所有代码
 ************************************************************************************************/
function page_construct_ui_step(obj, type, val, step_val, min_val, max_val, val_chg_fun) {
    obj.set_type(type);
    obj.set_min_val(min_val);
    obj.set_step_val(step_val);
    obj.set_max_val(max_val);
    obj.set_val(val);
    obj.on_val_chg = val_chg_fun;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置编辑组文字垂直；此方法在语言修改的情况之后需要调用
 * 参数:
 *    NA
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    此方法运用于固定格式的html;
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.5.4
 *      内容 : 所有代码
 ************************************************************************************************/
function set_text_vertical() {
    $(".item_div").each(function () {
        var $this = $(this);
        var b_is_show = $this.find(".edit_item_gp").hasClass("toggle_edit_item_gp");
        var item_edit_title = $this.find(".edit_title");

        if (!item_edit_title.length) {
            return;
        }

        var span_val = item_edit_title.text();

        // 匹配全英文
        var reg_en = /^[A-Za-z]*$/;
        // 匹配<br>
        var reg_br = /<br\s*.?>/g;
        var span_val_no_space = span_val.trim().replace(/\s*/g, "");
        var b_is_en = reg_en.test(span_val_no_space);


        if (b_is_show) {
            var span_lan = span_val.length;
            var new_val = "";

            if (b_is_en) {
                span_val = span_val.split(" ");
                span_lan = span_val.length;
            }

            for (var idx_i = 0; idx_i < span_lan; idx_i++) {
                var element = span_val[idx_i];

                if (idx_i !== span_lan - 1) {
                    new_val += element + "<br>";
                } else {
                    new_val += element;
                }
            }
            item_edit_title.html(new_val).css("height", "100%");
        } else {
            if (b_is_en) {
                var set_span_val = item_edit_title.html().replace(reg_br, " ");

                item_edit_title.html(set_span_val).css("height", "auto");
            } else {
                item_edit_title.html(span_val).css("height", "auto");
            }
        }
    });
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    编辑组切换展开隐藏函数；
 * 参数:
 *    @param { Promise<Object>} el jq对象:需要切换的编辑组外框div
 *    @param { Promise<Boolean>} multiple 是否只展开一个
 *    @param { Promise<Boolean>} updateScrool 是否更新滚动条插件
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    此方法运用于固定格式的html;
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.5.4
 *      内容 : 所有代码
 ************************************************************************************************/
var mc_edit_gp_toggle = function (el, multiple, updateScrool) {
    this.el = el || {};
    this.multiple = multiple || false;
    this.updateScrool = updateScrool || false;
    var obj_edit_title = this.el.find(".edit_title");

    obj_edit_title.on("click", {
        el: this.el,
        multiple: this.multiple,
        updateScrool: this.updateScrool
    },
    this.toggle_fold);
};


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    mc_edit_gp_toggle 属性 toggle_fold 点击事件调用函数；
 * 参数:
 *    @param { Promise<String>} e 外部传递数据对象；需要切换的编辑组外框div
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    此方法运用于固定格式的html;
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.5.4
 *      内容 : 所有代码
 ************************************************************************************************/
mc_edit_gp_toggle.prototype.toggle_fold = function (e) {
    var $el = e.data.el;
    var $this = $(this);
    // $next === $this.siblings(".edit_item_gp")
    var $next = $this.next();

    $next.toggleClass("toggle_edit_item_gp");

    var b_is_show = $next.hasClass("toggle_edit_item_gp");
    var span_val = $this.text();
    // 匹配全英文
    var reg_en = /^[A-Za-z]*$/;
    // 匹配<br>
    var reg_br = /<br\s*.?>/g;
    var span_val_no_space = span_val.trim().replace(/\s*/g, "");
    var b_is_en = reg_en.test(span_val_no_space);

    if (b_is_show) {
        var span_lan = span_val.length;
        var new_val = "";

        if (b_is_en) {
            span_val = span_val.split(" ");
            span_lan = span_val.length;
        }

        for (var idx_e = 0; idx_e < span_lan; idx_e++) {
            var element_e = span_val[idx_e];

            if (idx_e !== span_lan - 1) {
                new_val += element_e + "<br>";
            } else {
                new_val += element_e;
            }
        }
        $this.html(new_val).css("height", "100%");
    } else {
        if (b_is_en) {
            var set_span_val = $this.html().replace(reg_br, " ");

            $this.html(set_span_val).css("height", "auto");
        } else {
            $this.html($this.text()).css("height", "auto");
        }
    }

    // 更新滚动条
    if (e.data.updateScrool) {
        $el.getNiceScroll().resize();
    }
};


/************************************************************************************************
* 类型:
*    函数
* 功能:
*    从数组格式类型的字符串获取值；
* 参数:
*    @param { Promise<String>} str_arr 类数组字符串；
*    @param { Promise<String>} val 值字符串；
* 返回:
*    @returns { Promise<String>} 找到的对应值 || false；
* 例子:
*    输入:参数1: "1=MC_LANG_OPTION_STR_1_DSP,3=MC_LANG_OPTION_STR_3_DSP,4=MC_LANG_OPTION_STR_4_DSP"
           参数2: "1"
     返回:"MC_LANG_OPTION_STR_1_DSP
* 备注:
*    此方法类数组字符串为固定格式:”key1=val1,key2=val2" 类型
* 修改:
*   1. 类型 : 创建
*      作者 : 巫昭雯
*      时间 : 2020.5.4
*      内容 : 所有代码
************************************************************************************************/
function get_val_from_str_arr(str_arr, val) {
    if ("string" !== typeof str_arr) {
        return false;
    }

    var str_split = str_arr.split(",");
    var arr_len = str_split.length;

    for (var idx = 0; idx < arr_len; idx++) {
        var item = str_split[idx];

        if (-1 !== item.indexOf("=")) {
            var item_key = item.split("=")[0];

            if (item_key === val) {
                return item.split("=")[1];
            }
        }
    }
    return false;
}


/************************************************************************************************
* 类型:
*    函数
* 功能:
*    计算单项尺寸; 设置css尺寸值；单项占100%的多少；
* 参数:
*    @param { Promise<Number>} len 总项目数；
*    @param { Promise<String>} step 尺寸差值；为带单位的css值
*    @param { Promise<Boolean>} b_add 差值为加还是减
* 返回:
*    @returns { Promise<String>} css calc值 || false
* 例子:
*    输入:(3,"7px",false)
     返回:"calc(33% - 7px)"
* 备注:
*    NA
* 修改:
*   1. 类型 : 创建
*      作者 : 巫昭雯
*      时间 : 2020.5.12
*      内容 : 所有代码
************************************************************************************************/
function mc_page_calc_item_size(len, step, b_add) {
    if ("number" !== typeof len || "string" !== typeof step || "boolean" !== typeof b_add) {
        return false;
    }

    if (0 === len) {
        return false;
    }

    var size = Number((100 / len)).toFixed() + "%";
    var re_val = "";

    if (b_add) {
        re_val = "calc(" + size + " + " + step + ")";
    } else {
        re_val = "calc(" + size + " - " + step + ")";
    }

    return re_val;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置可编辑属性(contenteditable)；全局
 * 参数:
 *    @param { Promise<Boolean>} b 可编辑 (true) || 不可编辑 (false)
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    设置对象:页面上全局搜索的带有可编辑属性的标签
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.5.21
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_page_set_attr_contenteditable(b) {
    if ("boolean" !== typeof b) {
        return;
    }

    $("[contenteditable]").each(function (idx, el) {
        // el.setAttribute("contenteditable",b);
        el.contentEditable = b;
    });
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取指定样式名在样式表的下标
 * 参数:
 *    @param { Promise<String>} cur_page_stylesheet 当前样式表
 *    @param { Promise<String>} class_name 样式名称
 * 返回:
 *     @returns { Promise<Number>} 找到的下标 || false
 * 例子:
 *    NA
 * 备注:
 *    设置对象:页面上全局搜索的带有可编辑属性的标签
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.6.5
 *      内容 : 所有代码
 ************************************************************************************************/
function get_css_class_idx(cur_page_stylesheet, class_name) {
    var arr_css_class = cur_page_stylesheet.cssRules;
    var css_len = arr_css_class.length;

    for (var css_i = 0; css_i < css_len; css_i++) {
        var item = arr_css_class[css_i];

        if (item.selectorText === class_name) {
            return css_i;
        }
    }
    return false;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    按钮弹出菜单
 * 参数:
 *    @param { Promise<Object>} el 带有弹出菜单布局的外层div jq对象
 *    @param { Promise<Boolean>} multiple: 是否可同时显示多个弹出菜单
 *    @param { Promise<Boolean>} b_hover: 是否为hover触发 默认为按钮点击触发
 * 返回:
 *    NA
 * 例子:
 *    布局例子:
 *       <div class="mc_btn_pop_menu_wrap">
 *          <div class="mc_btn_pop_menu_btn"></div>
 *          <div class="mc_btn_pop_menu_box"></div>
 *       </div>
 * 备注:
 *    按钮弹出菜单布局为:外层类 mc_btn_pop_menu_wrap 包裹 按钮类:mc_btn_pop_menu_btn 和 菜单盒子类: mc_btn_pop_menu_box
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2020.5.21
 *      内容 : 所有代码
 ************************************************************************************************/
var mc_btn_pop_menu = function (el, multiple, b_hover) {
    this.el = el || {};
    this.multiple = multiple || false;
    this.b_hover = b_hover || false;

    // current open mc_btn_pop_menu_wrap obj
    this.on_click_chg = null;
    this.before_open = null;

    // defined class name
    var str_wrap_cname = ".mc_btn_pop_menu_wrap";
    var str_btn_cname = ".mc_btn_pop_menu_btn";
    var str_box_cname = ".mc_btn_pop_menu_box";

    var $obj_wrap = this.el.find(str_wrap_cname);
    var $obj_btn = $obj_wrap.find(str_btn_cname);

    if (this.b_hover) {
        $obj_wrap.on("mouseenter", {
            el: this.el,
            c_this: this
        }, mouseenter_wrap_obj);
    } else {
        $obj_btn.on("click", {
            el: this.el,
            // consrtuct this
            c_this: this
        }, click_btn_pop_menu);
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    切换菜单显示隐藏（点击弹出菜单按钮弹出或是关闭菜单）
     * 参数:
     *    @param { Promise<Object>} e 按钮点击事件参数对象
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 巫昭雯
     *      时间 : 2020.5.21
     *      内容 : 所有代码
     ************************************************************************************************/
    function click_btn_pop_menu(e) {
        var $this = $(this);
        // console.log($this);
        // var $el = e.data.el;

        var c_this = e.data.c_this;

        if (!c_this.multiple) {
            var $obj_wrap_this = $this.parent(str_wrap_cname);
            var $obj_wrap_others = $obj_wrap.not($obj_wrap_this);

            $obj_wrap_others.find(str_box_cname).slideUp();
        }

        var $obj_meun = $this.siblings(str_box_cname);

        if (!$obj_meun.is(":animated")) {
            if ("none" === $obj_meun.css("display") && "function" === typeof c_this.before_open) {
                c_this.before_open($this.parent(str_wrap_cname));
            }

            $obj_meun.slideToggle("normal", function () {
                if ("none" !== $obj_meun.css("display")) {
                    // update this open obj
                    if ("function" === typeof c_this.on_click_chg) {
                        c_this.on_click_chg($this.parent(str_wrap_cname));
                    }

                    // Viewable area
                    var view_rect = document.body.getBoundingClientRect();
                    var cur_rect = $obj_meun[0].getBoundingClientRect();
                    // current obj
                    // var cur_width = $obj_meun.clientWidth;
                    // var cur_left = $obj_meun[0].offsetLeft;

                    // over view area
                    var over_val = cur_rect.width + cur_rect.x - view_rect.width;

                    if (0 < over_val) {
                        // var cur_left = $obj_meun.css("left");
                        // $obj_meun.css("left",cur_left - over_val + "px");
                    }
                }
            });
        }
    }

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    关闭所有弹出菜单；所有菜单外的按钮关闭
     * 参数:
     *    @param { Promise<Object>} obj 触发点击事件对象
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 巫昭雯
     *      时间 : 2020.5.21
     *      内容 : 所有代码
     ************************************************************************************************/
    this.close_menu = function (obj) {
        var b_stop = true;

        $obj_wrap.each(function name(idx, ele) {
            if (ele.contains(obj)) {
                b_stop = false;
                return;
            }
        });

        if (b_stop) {
            $obj_wrap.find(str_box_cname).slideUp();
        }
    };


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    关闭当前菜单；当前菜单内的按钮事件关闭
     * 参数:
     *    @param { Promise<Object>} obj 触发点击事件对象
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 巫昭雯
     *      时间 : 2020.6.12
     *      内容 : 所有代码
     ************************************************************************************************/
    this.close_cur_menu = function (obj) {
        if (obj) {
            $obj_wrap.each(function name(idx, ele) {
                if (ele.contains(obj)) {
                    $(ele).find(str_box_cname).slideUp();
                    return;
                }
            });
        }
    };


    function mouseenter_wrap_obj(e) {
        e.stopPropagation();

        var $this = $(this);
        var c_this = e.data.c_this;

        if (!c_this.multiple) {
            $obj_wrap.not($this).find(str_box_cname).slideUp();
        }

        var $obj_meun = $this.find(str_box_cname);

        if (!$obj_meun.is(":animated")) {
            if ("block" !== $obj_meun.css("display")) {
                $obj_meun.slideDown();
                // $this.mouseleave(btn_mouseleave);
            }
        }
    }
};


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    添加字符串项的前缀名
 * 参数:
 *    @param { Promise<String> } str 需要转化的字符串
 *    @param { Promise<String> } prefix 需要添加的每一项相同的前缀名
 *    @param { Promise<String> } lang_map 可选参数 语言表(若参数不为空则返回的数据是已经翻译了的); 该参数为空时返回的数据不带翻译；
 * 返回:
 *    @returns { Promise<String> } new_str 返回的新字符串 || false
 * 例子:
 *    var new_str = mc_add_item_prefix("1,,5,","MC_LANG_");
 *    返回值 new_str = "1=MC_LANG_1,5=MC_LANG_5"
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-08-29
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_add_item_prefix(str, prefix, lang_map) {
    if ("string" !== typeof str || "string" !== typeof prefix) {
        return false;
    }

    var str_delimiter = ",";
    var link_symbol = "=";

    var arr = str.split(str_delimiter);
    var len = arr.length;

    var new_str = "";

    for (var idx = 0; idx < len; idx++) {
        var item = arr[idx];

        if ("" === item.trim()) {
            continue;
        }
        var str_lang_splice = prefix + item;

        if ("object" === typeof lang_map) {
            if (Object.prototype.hasOwnProperty.call(lang_map, str_lang_splice)) {
                str_lang_splice = lang_map[str_lang_splice];
            }
        }

        new_str += item + link_symbol + str_lang_splice + str_delimiter;
    }

    var last = new_str.lastIndexOf(str_delimiter);

    if ("-1" !== last) {
        return new_str.substring(0, last);
    }

    return new_str;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    随机生成颜色值
 * 参数:
 *    NA
 * 返回:
 *    @returns { Promise<String> } 生成的颜色值 16进制
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-03
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_random_color() {
    var arr_color = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];
    var color = "";

    for (var i = 0; 6 > i; i++) {
        var random = Math.floor(Math.random() * 16);

        color += arr_color[random];
    }

    return "#" + color;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    添加css规则
 * 参数:
 *    @param { Promise<String> } stylesheets_name 样式表名称 id
 *    @param { Promise<String> } rule_name 规则名称
 *    @param { Promise<String> } str_style_rule 样式规则
 * 返回:
 *    @returns { Promise<Object> } true || false
 * 例子:
 *    NA
 * 备注:
 *    规则名称包含了css选择符 eg:  ".block" || "#wrap_div" || span
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-03
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_add_css_rules(stylesheets_name, rule_name, str_style_rule) {
    if ("string" !== typeof stylesheets_name || "string" !== typeof rule_name || "string" !== typeof str_style_rule) {
        return false;
    }

    if ("" === stylesheets_name.trim() || "" === rule_name.trim() || "" === str_style_rule.trim()) {
        return false;
    }

    // var str_style_rule = "background-color:" + color_val + "!important;";

    var obj_styleSheets = document.styleSheets;

    for (var idx = 0; idx < obj_styleSheets.length; idx++) {
        var str_styles_id = obj_styleSheets[idx].ownerNode.id;

        if ("undefined" !== str_styles_id && stylesheets_name === str_styles_id) {
            var obj_cur_stylesheet = document.styleSheets[idx];
            var len = obj_cur_stylesheet.cssRules.length;

            var b_exist = false;

            for (var index = 0; index < len; index++) {
                var item = obj_cur_stylesheet.cssRules[index];

                if (!item) {
                    continue;
                }

                // && 0 !== item.styleMap.size  no compatible software
                if (item.selectorText === rule_name) {
                    b_exist = true;
                    break;
                }
            }

            if (!b_exist) {
                obj_cur_stylesheet.addRule(rule_name, str_style_rule);
            }

            return true;
        }
    }

    return true;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    创建饼状进度条构造函数
 * 参数:
 *    NA
 * 返回:
 *    @returns { Promise<Object> } 可创建饼状图的对象
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-16
 *       内容 : 所有代码
 ************************************************************************************************/
var mc_progress_circle = function () {
    var progress = {
        textheight: null,
        /************************************************************************************************
         * 类型:
         *    函数
         * 功能:
         *    渲染一个饼状图进程图；
         * 参数:
         *    @param { Promise<String> } id 渲染外层div id
         *    @param { Promise<Number> } r 进度条宽度
         *    @param { Promise<Number> } percent 目前进度条百分比 不加符号
         *    @param { Promise<Number> } color 该区间内日的颜色值
         * 返回:
         *    @returns { Promise<String> } true  === 成功 || false === 参数错误
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2020-09-16
         *       内容 : 所有代码
         ************************************************************************************************/
        render_one: function (id, r, percent, color) {
            if ("string" !== typeof id || "number" !== typeof r || "number" !== typeof percent) {
                return false;
            }
            var canvas = document.getElementById(id);

            if (!canvas) {
                return false;
            }

            var context = canvas.getContext("2d");
            var length = canvas.width;

            var i = 0;
            var step = 1.5;

            if (100 <= percent) {
                step = 3;
            }
            var interval = setInterval(function () {
                i += step;
                progress.render(context, length, r, i, percent, color);
                if (100 <= i) {
                    clearInterval(interval);
                    return;
                }

                if (i >= percent) {
                    clearInterval(interval);
                }
            }, 10);

            return true;
        },
        render: function (context, length, r, i, percent, color) {
            context.clearRect(0, 0, length, length);
            // wrap circle
            context.beginPath();
            var gradient = context.createLinearGradient(length, 0, 0, 0);

            // gradient = context.createLinearGradient(length / 2 , 0, 0, 0);

            // circle color
            // gradient.addColorStop("0", "#76EEC6");
            // gradient.addColorStop("1.0", "#63B8FF");

            var color_val = color || "#54DDAF";

            gradient.addColorStop("0", color_val);

            context.strokeStyle = gradient;
            context.lineWidth = r;
            context.arc(
                length / 2,
                length / 2,
                length / 2 - r,
                -0.5 * Math.PI,
                -0.5 * Math.PI + i * 0.02 * Math.PI,
                false
            );
            context.stroke();
            context.closePath();

            // hearder cercle
            context.beginPath();
            context.strokeStyle = "#8d8d8d";
            context.lineWidth = 2;
            context.fillStyle = "#ffffff";
            // context.arc(length / 2, r, 0.6 * r, 0, 2 * Math.PI, false);
            context.stroke();
            context.fill();
            context.closePath();

            //   footer cercle
            context.beginPath();
            //   var radian = (percent / 100) * 2 * Math.PI - 0.5 * Math.PI;
            //   var x = Math.cos(radian) * (length / 2 - r) + length / 2;
            //   var y = Math.sin(radian) * (length / 2 - r) + length / 2;
            //   context.arc(x, y, 0.6 * r, 0, 2 * Math.PI, false);
            context.stroke();
            context.fill();
            context.closePath();

            // 饼圆圈 color
            context.beginPath();
            context.lineWidth = 1;
            context.strokeStyle = color_val;
            context.fillStyle = color_val;
            context.arc(length / 2, length / 2, length / 2 - 2 * r, 0, 2 * Math.PI);
            context.fill();
            context.closePath();

            // text
            context.beginPath();
            // context.font = "bold " + (length / 2 - 2.5 * r) / 2 + "px 微软雅黑";
            context.fillStyle = "#ffffff";
            var text = percent + "%";

            var textwidth = context.measureText(text).width;

            if (null === this.textheight) {
                var div = document.createElement("div");

                document.body.appendChild(div);
                div.innerHTML = text;
                div.style.fontSize = (length / 2 - 2.5 * r) / 2 + "px";
                this.textheight = div.offsetHeight;
                div.parentNode.removeChild(div);
            }
            var textheight = this.textheight;

            context.fillText(
                text,
                (length - textwidth) / 2,
                length / 2 + textheight / 4
            );
            context.fill();
            context.closePath();
        }
    };

    return progress;
};


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取进度条控件html字符串
 * 参数:
 *    @param { Promise<String> } title 该控件的标题
 *    @param { Promise<Number> } width 进度条占的百分比(不带%符号)
 *    @param { Promise<String> } color 进度条颜色
 * 返回:
 *    @returns { Promise<String> } 返回的html字符串 || "" === 参数错误
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-16
 *       内容 : 所有代码
 ************************************************************************************************/
function get_progress_bar_html(title, width, color) {
    if ("number" !== typeof width || "string" !== typeof title || "string" !== typeof color) {
        return "";
    }

    // if ("" === color.trim()) {
    //     return "";
    // }

    var default_color = color || "#86e01e";
    var html = "";
    var show_percent = width;

    if (100 < Number(width)) {
        show_percent = 100;
    }

    html = "<div class='item_pro_block'><div class='mc_lab' style=''>" + title + "</div><div class='mc_lab' style=''> " +
        width + "%</div><div class='mc_progress_bar_wrap' style=''><div class='mc_progress_bar' style='width:" +
        show_percent + "%;background-color:" + default_color + "'></div></div></div>";

    return html;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取进度条当前占比值
 * 参数:
 *    @param { Promise<String> } grp_width 一组矩形宽
 *    @param { Promise<String> } grp_height 一组矩形宽
 * 返回:
 *    @returns { Promise<Object> } 对象内包含属性参考备注  || false === 参数错误
 * 例子:
 *    NA
 * 备注:
 *    属性1 val(Number) === 占进度条的百分比；pre_val(String) === 带符号的百分比；color(String) === 该百分比区域的颜色值
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-16
 *       内容 : 所有代码
 ************************************************************************************************/
function get_progress_value(grp_width, grp_height) {
    if ("number" !== typeof grp_width || "number" !== typeof grp_height) {
        return false;
    }

    // defiend color is from small to large
    var arr_color = ["#86e01e", "#f2d31b", "#f2b01e", "#f27011", "#f63a0f", "red"];
    var ui_color_len = arr_color.length;

    // divisor clacular percent Base value
    var ui_divisor = 650000;
    var val = (grp_width * grp_height) / ui_divisor;

    // Converted to percentage
    val = Number((val * 100).toFixed(2));

    if (100 < val) {
        return {
            pre_val: val + "%",
            val: Number(val),
            color: arr_color[ui_color_len - 1]
        };
    }

    // clac percent
    var step = (100 / ui_color_len);
    // current percent value in color index
    var cur_c_i = Math.floor(val / step);

    return {
        // add percent symbol
        pre_val: val + "%",
        val: Number(val),
        color: arr_color[cur_c_i]
    };
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    添加分割div 竖向
 * 参数:
 *    @param { Promise<Object> } arr_obj 需要添加的分割jq对象集合
 * 返回:
 *    @returns { Promise<Boolean> } true || false
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-09-16
 *       内容 : 所有代码
 ************************************************************************************************/
function add_split_line_vertical(arr_obj) {
    if ("object" !== typeof arr_obj) {
        return false;
    }

    if ("[object Object]" !== Object.prototype.toString.call(arr_obj)) {
        return false;
    }

    if (0 === arr_obj.length) {
        return false;
    }

    if (!arr_obj.each) {
        return false;
    }

    if ("function" !== typeof arr_obj.each) {
        return false;
    }

    var str_spilt_html = "<div class='mc_spilt_div_vertical'></div>";
    var ui_idx = 0;

    arr_obj.each(function (idx, el) {
        if (!el) {
            return true;
        }

        if ("none" === el.style.display) {
            return true;
        }

        if (0 === ui_idx) {
            ui_idx += 1;
            return true;
        }

        $(el).before(str_spilt_html);
        ui_idx += 1;

        return true;
    });


    return true;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *   获取计算数组前n项得和
 * 参数:
 *    @param { Promise<String> } arr 需要计算的数组
 *    @param { Promise<String> } idx 需要获取的前几项
 * 返回:
 *    @returns { Promise<String> } 计算后的值
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-1-8
 *       内容 : 所有代码
 ************************************************************************************************/
function get_sum_idx(arr, idx) {
    var re_data = arr.reduce(function (pre, cur, index) {
        if (index > idx) {
            return pre + 0;
        }
        return pre + cur;
    });

    return re_data;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    删除css规则
 * 参数:
 *    @param { Promise<String> } stylesheets_name 样式表名称 id
 *    @param { Promise<String> } rule_name 规则名称
 *    @param { Promise<Number> } type 删除模式 1 === 全等模式 || 其他 === 包含模式
 * 返回:
 *    @returns { Promise<Object> } true || false
 * 例子:
 *    NA
 * 备注:
 *    规则名称包含了css选择符;
 *    全等模式: 删除的css规则名称全等于传递的参数规则名称；
 *    包含模式: 只要检索到的css规则包含传参的规则名称字符串就删除该样式；
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-1-8
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_delete_css_rules(stylesheets_name, rule_name, type) {
    if ("string" !== typeof stylesheets_name || "string" !== typeof rule_name || "number" !== typeof type) {
        return false;
    }

    if ("" === stylesheets_name.trim() || "" === rule_name.trim()) {
        return false;
    }

    var obj_styleSheets = document.styleSheets;

    for (var idx = 0; idx < obj_styleSheets.length; idx++) {
        var str_styles_id = obj_styleSheets[idx].ownerNode.id;

        if ("undefined" !== str_styles_id && stylesheets_name === str_styles_id) {
            var obj_cur_stylesheet = document.styleSheets[idx];
            var len = obj_cur_stylesheet.cssRules.length;

            for (var index = 0; index < len; index++) {
                var item = obj_cur_stylesheet.cssRules[index];

                if (!item) {
                    continue;
                }

                if (-1 === item.selectorText.indexOf(rule_name)) {
                    continue;
                }

                if (1 === type && item.selectorText === rule_name) {
                    // Congruent mode
                    obj_cur_stylesheet.deleteRule(index);
                    index -= 1;
                    continue;
                }

                // Blur mode
                obj_cur_stylesheet.deleteRule(index);
                index -= 1;
            }

            return true;
        }
    }

    return true;
}


function get_progress_color(percent) {
    if ("number" !== typeof percent) {
        return false;
    }

    // defiend color is from small to large
    var arr_color = ["#86e01e", "#f2d31b", "#f2b01e", "#f27011", "#f63a0f", "red"];
    var ui_color_len = arr_color.length;
    var val = percent;

    if (100 < val) {
        return arr_color[ui_color_len - 1];
    }

    // clac percent
    var step = (100 / ui_color_len);
    // current percent value in color index
    var cur_c_i = Math.floor(val / step);

    return arr_color[cur_c_i];
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    复制对象; 复制对象的属性和属性值
 * 参数:
 *    @param { Promise<Object> } obj 复制的对象
 * 返回:
 *    @returns { Promise<Object> } 返回复制后生成的对象 || false
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-10-19
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_copy_obj(obj) {
    if ("[object Object]" !== Object.prototype.toString.call(obj)) {
        return false;
    }

    var obj_copy = {};
    var arr_key = Object.keys(obj);
    var ui_key_len = arr_key.length;

    for (var key_i = 0; key_i < ui_key_len; key_i++) {
        var str_key = arr_key[key_i];

        obj_copy[str_key] = obj[str_key];
    }

    return obj_copy;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    判断参数是否为数组数据类型；数据类型校验函数
 * 参数:
 *    @param { Promise<Array> } arr
 * 返回:
 *    @returns { Promise<Boolean> } true || false
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-10-21
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_is_array(arr) {
    if ("[object Array]" === Object.prototype.toString.call(arr)) {
        return true;
    }
    return false;
}

/************************************************************************************************
 * 类型:
 *    校验函数
 * 功能:
 *    判断参数是否为对象数据类型；数据类型校验函数
 * 参数:
 *    @param { Promise<String> } obj 对象
 * 返回:
 *    @returns { Promise<Boolean> } true || false
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-10-21
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_is_object(obj) {
    if ("[object Object]" === Object.prototype.toString.call(obj)) {
        return true;
    }
    return false;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取当前页面的缩放值
 * 参数:
 *    NA
 * 返回:
 *    @returns { Promise<Number> } 页面缩放整数值；无缩放时 === 100;
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-11-04
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_get_page_zoom() {
    var ratio = 0,
        screen = window.screen,
        ua = navigator.userAgent.toLowerCase();

    if (window.devicePixelRatio) {
        ratio = window.devicePixelRatio;
    } else if (~ua.indexOf("msie")) {
        if (screen.deviceXDPI && screen.logicalXDPI) {
            ratio = screen.deviceXDPI / screen.logicalXDPI;
        }
    } else if (window.outerWidth && window.innerWidth) {
        ratio = window.outerWidth / window.innerWidth;
    }

    if (ratio) {
        ratio = Math.round(ratio * 100);
    }
    return ratio;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    四舍五入特殊处理
 * 参数:
 *    @param { Promise<Number> } ui_mun 待处理值
 * 返回:
 *    @returns { Promise<String> } 处理后的值 || false === 参数为undefined
 * 例子:
 *    NA
 * 备注:
 *    小数点后的第一位 === 5 && 第二位存在时 才进位
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-11-24
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_round(ui_mun) {
    if ("undefined" === typeof ui_mun) {
        return false;
    }

    var arr = ui_mun.toString().split(".");
    var ui_int = arr[0];
    var ui_xiash = arr[1];

    if (ui_xiash) {
        if (5 < Number(ui_xiash[0])) {
            return Number(ui_int) + 1;
        }

        if (5 === Number(ui_xiash[0]) && Number(ui_xiash[1])) {
            return Number(ui_int) + 1;
        }

        return Number(ui_int);
    }
    return ui_mun;
}


/************************************************************************************************
 * 类型:
 *    构造函数
 * 功能:
 *    弹窗联动注册
 * 参数:
 *    NA
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    注册全局对象成功之后:
 *      1. 先注册页面 调用 new_page_key()
 *      2. 1返回的对象；
 *         a: 调用设置参数(在url无参数情况下这步可无) set_opt;
 *         b: 调用设置类型 set_type;
 *         c: 调用注册函数 set_fun;
 *      3. 在需要触发注册函数的地方使用 link_data() ;
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-24
 *       内容 : 所有代码
 ************************************************************************************************/
function construct_page_popup_link_data() {
    // 注册页面map对象
    var m_obj_page_map = {};
    var str_symbol = "</br>";
    // param obj
    var obj_fun_type = function (type, fun) {
        return {
            fun: fun,
            type: type
        };
    };


    /************************************************************************************************
     * 类型:
     *    构造函数
     * 功能:
     *    为弹窗页创建新的参数; url param
     * 参数:
     *    @param { Promise<String> } key_name 参数名;
     * 返回:
     *    @returns { Promise<Boolean> } true === 成功 || false === 参数错误
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-12-28
     *       内容 : 所有代码
     ************************************************************************************************/
    var obj_new_param = function (key_name) {
        var m_obj_params = {};
        var str_url_param = "no_param";
        var c_str_url_param_def = "no_param";

        if ("string" !== typeof key_name) {
            return false;
        }

        /************************************************************************************************
         * 类型:
         *    接口
         * 功能:
         *    设置该页参数键值对; 若页面无参数则默认参数为 "no_param"
         * 参数:
         *    @param { Promise<String> } key 参数key
         *    @param { Promise<String> } val 参数value
         * 返回:
         *    @returns { Promise<Boolean> } true === 设置成功 || false === 参数错误
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2020-12-28
         *       内容 : 所有代码
         ************************************************************************************************/
        this.set_opt = function (key, val) {
            if ("string" !== typeof key || "string" !== typeof val) {
                return false;
            }

            if ("" !== key.trim() && "" !== val.trim()) {
                str_url_param = key.trim() + "=" + val.trim();
            }

            m_obj_params[str_url_param] = new obj_fun_type();

            return true;
        };

        /************************************************************************************************
         * 类型:
         *    接口
         * 功能:
         *    设置弹窗触发类型; eg: 选择 === ["select"]; 由构造实例确定;
         * 参数:
         *    @param { Promise<Array> } type 类型数组;
         * 返回:
         *    @returns { Promise<Boolean> } true === 设置成功 || false === 参数错误
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2020-12-28
         *       内容 : 所有代码
         ************************************************************************************************/
        this.set_type = function (type) {
            if (!mc_util_is_array(type)) {
                return false;
            }

            var arr_type = type.join(str_symbol);

            if (!mc_util_is_object(m_obj_params[str_url_param]) && c_str_url_param_def === str_url_param) {
                m_obj_params[str_url_param] = new obj_fun_type();
                m_obj_params[str_url_param].type = arr_type;
            } else {
                m_obj_params[str_url_param].type = arr_type;
            }

            return true;
        };

        /************************************************************************************************
         * 类型:
         *    接口
         * 功能:
         *    设置注册函数；
         * 参数:
         *    @param { Promise<Function> } fun 该参数下调用的函数;
         * 返回:
         *    @returns { Promise<Boolean> } true === 设置成功 || false === 参数错误
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2020-12-28
         *       内容 : 所有代码
         ************************************************************************************************/
        this.set_fun = function (fun) {
            if ("function" !== typeof fun) {
                return false;
            }

            m_obj_params[str_url_param].fun = fun;

            return true;
        };

        /************************************************************************************************
         * 类型:
         *    接口
         * 功能:
         *    校验类型(触发类型)
         * 参数:
         *    @param { Promise<String> } opt_key 参数key
         *    @param { Promise<String> } type 触发类型;
         * 返回:
         *    @returns { Promise<Boolean> } true === 设置成功 || false === 参数错误
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2020-12-28
         *       内容 : 所有代码
         ************************************************************************************************/
        this.check_type = function (opt_key, type) {
            var obj_in = m_obj_params[opt_key];

            if (!obj_in) {
                return false;
            }

            if (obj_in.type) {
                if (-1 !== obj_in.type.indexOf(type)) {
                    return true;
                }
            }

            return false;
        };

        /************************************************************************************************
         * 类型:
         *    接口
         * 功能:
         *    获取注册函数
         * 参数:
         *    @param { Promise<Array> } arr_param 参数数组对;
         *    @param { Promise<String> } type 触发类型
         * 返回:
         *    @returns { Promise<String> } 参数1
         * 例子:
         *    NA
         * 备注:
         *    现货去默认参数中; 若无再比较参数数组；
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2020-12-28
         *       内容 : 所有代码
         ************************************************************************************************/
        this.get_fun = function (arr_param, type) {
            if (!mc_util_is_array(arr_param) || "string" !== typeof type) {
                return false;
            }

            var obj_def = m_obj_params[c_str_url_param_def];

            if (obj_def) {
                var b_type = this.check_type(c_str_url_param_def, type);

                if (!b_type) {
                    return false;
                }

                return obj_def.fun;
            }

            var ui_len = arr_param.length;

            for (var ui_i = 0; ui_i < ui_len; ui_i++) {
                var item = arr_param[ui_i];

                if ("string" !== typeof item) {
                    continue;
                }

                item = item.trim();

                if ("" === item) {
                    continue;
                }

                var obj_param = m_obj_params[item];

                if (obj_param) {
                    var b_type_i = this.check_type(item, type);

                    if (b_type_i) {
                        return obj_param.fun;
                    }
                }
            }

            return true;
        };

        //  fun return
        return key_name;
    };


    /************************************************************************************************
     * 类型:
     *    接口
     * 功能:
     *    创建新页面key
     * 参数:
     *    @param { Promise<String> } key 页面名称， 带 ".html";
     * 返回:
     *    @returns { Promise<Object> } 返回注册成功的页面对象; || false === 参数错误；
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-12-28
     *       内容 : 所有代码
     ************************************************************************************************/
    this.new_page_key = function (key) {
        if ("string" !== typeof key) {
            return false;
        }

        key = key.trim();

        if ("" === key) {
            return false;
        }

        var str_page = m_obj_page_map[key];

        if (!str_page) {
            var obj_new_one = new obj_new_param(key);

            m_obj_page_map[key] = obj_new_one;
        }

        return m_obj_page_map[key];
    };


    /************************************************************************************************
     * 类型:
     *    接口
     * 功能:
     *    联动触发函数; 再需要触发注册函数的地方调用；
     * 参数:
     *    @param { Promise<String> } type 注册函数的类型； eg === "select" ;
     *    @param { Promise<String> } arr_sel 框选的模组；
     *    @param { Promise<Array> } window_dom main界面下的iframe层级
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    触发注册函数传参为: (obj_page, arr_sel, type)
     *    obj_page === 弹窗window对象；
     *    arr_sel === 框选模组
     *    type === 注册函数的类型
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-12-28
     *       内容 : 所有代码
     ************************************************************************************************/
    this.link_data = function (type, arr_sel, window_dom) {
        if ("string" !== typeof type || !mc_util_is_array(arr_sel)) {
            return;
        }

        var ui_len = arr_sel.length;
        var obj_iframe = document.getElementsByTagName("iframe");

        if (0 === obj_iframe.length) {
            obj_iframe = window_dom.getElementsByTagName("iframe");
            if (1 >= obj_iframe.length) {
                return;
            }
            obj_iframe = obj_iframe[1];
        }

        if (0 === ui_len || 0 === obj_iframe.length) {
            return;
        }

        var obj_i = obj_iframe[0] || obj_iframe;
        var obj_page = obj_i.contentWindow;
        var str_url = obj_i.src;
        var str_page_name = mc_util_get_url_page_name(str_url);
        var obj_new = m_obj_page_map[str_page_name];

        if (!obj_new) {
            return;
        }

        // get url param
        var ui_idx = str_url.indexOf("?");
        var arr_opt = [];

        if (-1 !== ui_idx) {
            var str_sub = str_url.substring(ui_idx + 1, str_url.length);
            var ui_anchor_i = str_sub.indexOf("#");

            if (-1 !== ui_anchor_i) {
                str_sub = str_sub.substring(0, ui_anchor_i);
            }

            arr_opt = str_sub.split("&");
        }

        var fun = obj_new.get_fun(arr_opt, type);

        if ("function" !== typeof fun) {
            return;
        }

        fun(obj_page, arr_sel, type);
    };
}


/************************************************************************************************
 * 类型:
 *    工具函数
 * 功能:
 *    获取url里的html页面名称
 * 参数:
 *    @param { Promise<String> } str_url
 * 返回:
 *    @returns { Promise<String> } 返回获取到的带 .html 的字符串 || false === 参数错误
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-24
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_get_url_page_name(str_url) {
    if ("string" !== typeof str_url) {
        return false;
    }

    var ui_idx = str_url.indexOf(".html");
    var ui_last_i = str_url.lastIndexOf("/");

    if (-1 === ui_idx || -1 === ui_last_i) {
        return false;
    }
    var str_page_name = str_url.substring(ui_last_i + 1, ui_idx + 5);

    if (0 === str_page_name.length) {
        return false;
    }

    return str_page_name;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    构造缩放鼠标滚轮事件; 兼容浏览器
 * 参数:
 *    @param { Promise<Function> } callback 回调事件; 回调参数; 1 = 放大 || 0 = 缩小
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-01-07
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_construct_zoom_mousewheel(callback) {
    if ("function" !== typeof callback) {
        return;
    }

    // 添加缩放界面滚动事件对象
    var obj_mouse_wheel = {
        fun_name: "mousewheel",
        juged_val: "wheelDelta",
        b_firefox: false
    };

    // firefox
    if (0 <= navigator.userAgent.indexOf("Firefox")) {
        obj_mouse_wheel.fun_name = "DOMMouseScroll";
        obj_mouse_wheel.juged_val = "detail";
        obj_mouse_wheel.b_firefox = true;
    }

    // 添加滚轮事件监听
    window.addEventListener(obj_mouse_wheel.fun_name, function (event) {
        mouse_wheel_fun(event, obj_mouse_wheel);
    }, {
        passive: false
    });


    // 鼠标滚轮事件
    function mouse_wheel_fun(event, params) {
        if (event.ctrlKey) {
            var b_in = 0 > event[params.juged_val];

            if (params.b_firefox === b_in) {
                callback(1);
            } else {
                callback(0);
            }
            event.preventDefault();
        }
    }
}


/************************************************************************************************
 * 类型:
 *    构造函数
 * 功能:
 *    设置标签块样式; style 字符串值
 * 参数:
 *    NA
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-01-21
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_format_style() {
    var m_arr_style = [];
    // var m_ui_num = 0;

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    函数功能
     * 参数:
     *    @param { Promise<String> } str_attr 样式名称
     *    @param { Promise<String> } val 样式设置的值
     *    @param { Promise<String> } unit 样式单位符号(为空时默认为"px"); 特殊情况 为 null 表示无单位(级别最高);
     * 返回:
     *    @returns { Promise<Boolean> } true === 设置成功 || false === 参数格式错误
     * 例子:
     *    NA
     * 备注:
     *    eg1: new mc_format_style().set_val("width", 80)
     *    eg2: new mc_format_style().set_val("width", 80, "%")
     *    eg3: new mc_format_style().set_val("position", none, null)
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-01-21
     *       内容 : 所有代码
     ************************************************************************************************/
    this.set_val = function (str_attr, val, unit) {
        if ("string" !== typeof str_attr || "undefined" === typeof val) {
            return false;
        }

        str_attr = str_attr.trim();

        if (!str_attr) {
            return false;
        }

        var str_css = str_attr + ":" + val;
        var str_unit = "px";

        if ("string" === typeof unit) {
            unit = unit.trim();

            if (!unit) {
                str_unit = unit;
            }
        }


        if (null === unit) {
            m_arr_style.push(str_css);
            return true;
        }

        str_css += str_unit;
        m_arr_style.push(str_css);
        return true;
    };


    // 清空数据
    this.clear_data = function () {
        m_arr_style = [];
        m_arr_style.length = 0;
    };


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    获取样式
     * 参数:
     *    NA
     * 返回:
     *    @returns { Promise<String> } 设置的样式值字符串
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-01-21
     *       内容 : 所有代码
     ************************************************************************************************/
    this.get_style = function () {
        // console.log(m_ui_num);
        return m_arr_style.join(";");
    };
}


/************************************************************************************************
 * 类型:
 *    工具函数
 * 功能:
 *    是否为dom节点对象
 * 参数:
 *    @param { Promise<Object> } obj dom 节点对象
 * 返回:
 *    @returns { Promise<Boolean> } true === dom 节点对象
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-01-25
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_is_object_dom(obj) {
    if ("object" === typeof HTMLElement) {
        return obj instanceof HTMLElement;
    }

    if (obj) {
        return "object" === typeof obj && 1 === obj.nodeType && "string" === typeof obj.nodeName;
    }

    return false;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    编辑组; 滚动条事件; 编辑组外层必须包含类 mc_edit_gp_wrap
 * 参数:
 *    NA
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-05-26
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_edit_gp_scroll_event() {
    // .mc_edit_gp_wrap touchmove
    var m_obj_swiper = null;
    var fn_init = function () {
        if (mc_istouch()) {
            return;
        }

        var obj_gp = $(".mc_edit_gp_wrap");

        if (!obj_gp.length) {
            return;
        }

        obj_gp.parent().addClass("mc_mobile_toolbar swiper-container");
        obj_gp.addClass("swiper-wrapper");

        var str_div = "<div class='item_div' style='width:5px'></div>";

        obj_gp.prepend(str_div).append(str_div);

        $(".mc_edit_gp_wrap .item_div").each(function () {
            if ("none" !== this.style.display) {
                $(this).addClass("swiper-slide");
            }
        });

        m_obj_swiper = new Swiper(".swiper-container", {
            slidesPerView: "auto",
            observer: true
        });
        // console.log(obj_swiper);
    };

    fn_init();

    this.update = function () {
        if (m_obj_swiper) {
            m_obj_swiper.update();
            // console.log("更新");
        }
    };
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    判断是否为微信内浏览器
 * 参数:
 *    NA
 * 返回:
 *    @returns { Promise<String> } 参数1
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-06-08
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_util_is_weixin() {
    //window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息，这个属性可以用来判断浏览器类型
    var ua = window.navigator.userAgent.toLowerCase();

    // MicroMessenger -> micromessenger
    if (-1 !== ua.indexOf("micromessenger")) {
        return true;
    }

    return false;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    文件加载点击触发事件; 微信加载文件特殊处理; 用于弹出文件选择器之前操作
 * 参数:
 *    @param { Promise<Object> } dom 触发事件input对象
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-06-08
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_load_file_onclick(dom) {
    if (mc_util_is_weixin()) {
        if (dom) {
            dom.accept = "*";
        }
    }
}


/************************************************************************************************
 * 类型:
 *    构造函数
 * 功能:
 *    全屏操作
 * 参数:
 *    NA
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-06-09
 *       内容 : 所有代码
 ************************************************************************************************/
function mc_full_screen() {
    // var m_arr_prefix = ["", "webkit", "moz", "ms"];
    // 是否支持 fullscreenEnabled
    // 当前全屏元素 fullscreenElement
    // 全屏 === requestFullScreen ; 关闭 ===  exitFullscreen
    var m_obj_doc = document;
    var m_this = this;

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    浏览器是否支持全屏api
     * 参数:
     *    NA
     * 返回:
     *    @returns { Promise<Boolean> } true === "支持"
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-06-09
     *       内容 : 所有代码
     ************************************************************************************************/
    this.io_is_enable = function () {
        var b_enable = m_obj_doc.fullscreenEnabled || m_obj_doc.webkitFullscreenEnabled || m_obj_doc.mozFullScreenEnabled || m_obj_doc.msFullscreenEnabled;

        if (true === b_enable) {
            // alert("支持全屏", b_enable);
            return true;
        }

        // alert("不支持全屏", b_enable);
        return true;
    };

    var b_is_enable = this.io_is_enable();

    this.io_get_full_ele = function () {
        var fn_el = m_obj_doc.fullscreenElement || m_obj_doc.webkitFullscreenElement || m_obj_doc.mozFullScreenElement || m_obj_doc.msFullscreenElement;

        return fn_el;
    };


    // 保存切换全屏时的回调函数; param : 0,1,2,false
    this.on_full_change = function () {};
    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    切换全屏
     * 参数:
     *    @param { Promise<Object> } o_el 触发全屏的元素
     *    @param { Promise<Function> } callback 回调函数
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    callback 参数1 code 备注:
     *      0 === 退出全屏;
     *      1 === 进入全屏;
     *      2 === 浏览器或版本不支持全屏;
     *      false === 其他错误
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-06-9
     *       内容 : 所有代码
     ************************************************************************************************/
    this.io_toogle = function (o_el, callback) {
        if ("function" === typeof callback) {
            this.on_full_change = callback;
        }

        if (!b_is_enable) {
            this.on_full_change(2);
            return;
        }

        if (!this.io_get_full_ele()) {
            o_el = o_el || m_obj_doc.documentElement;
            var fn_open = o_el.requestFullscreen || o_el.webkitRequestFullscreen || o_el.mozRequestFullScreen || o_el.msRequestFullscreen;

            if ("function" === typeof fn_open) {
                fn_open.call(o_el);
                return;
            }

            this.on_full_change(2);
            return;
        }

        // alert("exit");
        if (m_obj_doc.exitFullscreen) {
            m_obj_doc.exitFullscreen();
            return;
        } else if (m_obj_doc.webkitExitFullscreen) {
            m_obj_doc.webkitExitFullscreen();
            return;
        } else if (m_obj_doc.mozCancelFullScreen) {
            m_obj_doc.mozCancelFullScreen();
            return;
        } else if (m_obj_doc.msExitFullscreen) {
            m_obj_doc.msExitFullscreen();
            return;
        } else if (m_obj_doc.cancelFullScreen) {
            m_obj_doc.cancelFullScreen();
            return;
        }

        this.on_full_change(2);
        return;
    };


    add_evnet(m_obj_doc);
    function add_evnet(param_el) {
        param_el.addEventListener("fullscreenchange", full_event_chg);
        param_el.addEventListener("webkitfullscreenchange", full_event_chg);
        param_el.addEventListener("mozfullscreenchange", full_event_chg);
        param_el.addEventListener("MSFullscreenChange", full_event_chg);

        param_el.addEventListener("fullscreenerror", full_event_error);
        param_el.addEventListener("webkitfullscreenerror", full_event_error);
        param_el.addEventListener("mozfullscreenerror", full_event_error);
        param_el.addEventListener("MSFullscreenError", full_event_error);
    }

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    监听全屏切换;
     * 参数:
     *    @param { Promise<Object> } e 事件event
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-06-10
     *       内容 : 所有代码
     ************************************************************************************************/
    function full_event_chg(e) { //eslint-disable-line
        // console.log("全屏改变");
        var param = false;

        if (m_this.io_get_full_ele()) {
            param = 1;
            // console.log("in full mode");
        } else {
            param = 0;
            // console.log("Leaving full mode");
        }

        if ("function" === typeof m_this.on_full_change) {
            m_this.on_full_change(param);
        }
    }

    // 监听调用api报错
    function full_event_error(e) {
        m_this.on_full_change(false, e);
        return;
    }
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    禁止元素ontouchmove事件 默认操作
 * 参数:
 *    @param { Promise<Object> } doc 想要阻止的元素dom
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-07-31
 *       内容 : 所有代码
************************************************************************************************/
function mc_prevent_touchmove(doc) {
    if ("ontouchmove" in doc && "function" === typeof doc.addEventListener) {
        doc.addEventListener("touchmove", function (e) {
            e.preventDefault();
        }, {
            passive: false
        });
    }
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    构造按钮选项卡
 * 参数:
 *    @param { Promise<String> } id 容器id
 *    @param { Promise<Object> } obj tab标签数组|对象; 为lang_id值 eg:["MC_LANG_RECEIVER_CARD", "MC_LANG_SCREEN_CFG_CONNECT"]; eg2: {key:html, key2:html2}; 查看备注
 *    @param { Promise<Function> } callback 切换回调函数; 回调参数为选中的标签数组内的值 || 对象key
 *    @param { Promise<String> } selected 初始化选项(默认为传参内有效值第一个); 可为空 eg: MC_LANG_RECEIVER_CARD; || eg2: key
 * 返回:
 *    @returns { Promise<Boolean> } true || false
 * 例子:
 *    NA
 * 备注:
 *    1. 回调值的lang_id || key都经过处理 -> 转化为字符串&处理两边空格
 *    2. obj 为对象{key:html, key2:html2}; key为标签调用回调值标记，html为每一项目的html字串;
 *    3. obj 内key值可为字符串 || 数字
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-07-29
 *       内容 : 所有代码
************************************************************************************************/
function construct_btn_tabs(id, obj, callback, selected) {
    if ("object" !== typeof obj || "string" !== typeof id) {
        return false;
    }

    var obj_par = document.getElementById(id);

    if (!obj_par) {
        return false;
    }

    var str_attr = "";
    var html = "";

    switch (Object.prototype.toString.call(obj)) {
    case "[object Object]":
        str_attr = "KEY";
        for (var key in obj) {
            if (Object.hasOwnProperty.call(obj, key)) {
                if ("undefined" !== typeof key && key.toString().trim() && obj[key]) {
                    html += "<div class='btn_tab' control_type='tabs' KEY='" + key.toString().trim() + "'>" + obj[key] + "</div>\n";
                }
            }
        }
        break;
    case "[object Array]":
        str_attr = "lang_id";
        var len = obj.length;

        for (var idx = 0; idx < len; idx++) {
            if (obj[idx]) {
                var item = obj[idx].toString().trim();

                if (item) {
                    html += "<div class='btn_tab' control_type='tabs' lang_id='" + item + "'>" + item + "</div>\n";
                }
            }
        }
        break;
    default:
        return false;
    }

    if (!html.trim()) {
        return false;
    }

    // 初始化选择
    var b_init_sel = false;

    selected = "undefined" !== typeof selected && selected.toString().trim() ? selected.toString().trim() : 0;
    obj_par.innerHTML = "<div class='btn_tabs_wrap dbclick_unchecked'>" + html + "</div>";
    Array.prototype.forEach.call(obj_par.querySelectorAll(".btn_tab"), function (el, index) {
        el.onclick = function () {
            $(this).addClass("select").siblings().removeClass("select");
            console.log(this.getAttribute(str_attr));   // eslint-disable-line
            if ("function" === typeof callback) {
                callback(this.getAttribute(str_attr));
            }
        };

        if (!b_init_sel) {
            if (0 === selected) {
                if (0 === index) {
                    el.classList.add("select");
                    b_init_sel = true;
                }
            } else {
                if (selected && el.getAttribute(str_attr) === selected ) {
                    el.classList.add("select");
                    b_init_sel = true;
                }
            }
        }
    });

    if (!b_init_sel) {
        obj_par.querySelector(".btn_tab").classList.add("select");
    }
    return true;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    标签处理: 用于处理tab标签lang_id为拼接情况(eg: lang_id=屏1,可以处理忽略下标之前的语言);
 * 参数:
 *    NA
 * 返回:
 *    @returns { Promise<String> } 参数1
 * 例子:
 *    NA
 * 备注:
 *    1. lang_id 拼接情况为: 语言翻译前缀 + 下标值; eg: 屏1, 屏2: 语言翻译前缀为 "屏", 1,2为标签显示值;
 *    2. get_tabs_arr接口设置标签数量(返回的下标显示值从1开始); 一般get_idx接口返回值从0开始;
 *    3. 调用前置条件: init_lang
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-11-27
 *       内容 : 所有代码
************************************************************************************************/
construct_btn_tabs.prototype = {
    // 翻译后的标签前缀值
    str_prefix: "",
    // 初始化设置拼接lang_id前缀;
    // @str_prefix=语言翻译前缀 eg: obj_lang_map.MC_LANG_MONITOR_SCREEN
    init_lang: function (str_prefix) {
        if (!this.is_str_valid(str_prefix)) {
            return false;
        }
        this.str_prefix = str_prefix;
        return true;
    },
    // 获取标签数组; cnt=标签个数
    get_tabs_arr: function (cnt) {
        if (!this.is_str_valid(this.str_prefix) || 0 >= Number(cnt)) {
            return false;
        }
        var arr_tabs_menu = [];

        for (var idx = 0; idx < cnt; idx++) {
            arr_tabs_menu[idx] = this.str_prefix + (idx + 1);
        }
        return arr_tabs_menu;
    },
    // 获取标签下标; 返回值从0开始; tab_name为标签点击回调参数;
    get_idx: function (tab_name) {
        if (!this.is_str_valid(tab_name) || !this.is_str_valid(this.str_prefix)) {
            return false;
        }
        return Number(tab_name.split(this.str_prefix)[1]) - 1;
    },
    // 语言表转换;
    // @param id=标签外层容器id; str_prefix_new=新语言标签前缀;
    translate: function (id, str_prefix_new) {
        var obj_wrap = document.getElementById(id);

        if (!obj_wrap) {
            return false;
        }
        var old_prefix = this.str_prefix;
        var new_prefix = str_prefix_new;

        if (!this.is_str_valid(old_prefix) || !this.is_str_valid(new_prefix)) {
            return false;
        }

        var m_this = this;

        $(obj_wrap).find(".btn_tabs_wrap .btn_tab").each(function (dom, idx) {  /* eslint-disable-line */
            if ( m_this.is_str_valid($(this).attr("lang_id")) ) {
                var new_value = $(this).attr("lang_id").replace(old_prefix, new_prefix);

                $(this).attr("lang_id", new_value).text(new_value);
            }
        });

        this.init_lang(str_prefix_new);
        return true;
    },
    // 判断字符串是否有效
    is_str_valid: function (str) {
        if ("string" !== typeof str || !str.trim()) {
            return false;
        }
        return true;
    }
};
